package org.bdware.irs.backend.servicesImpl;

import org.bdware.irs.backend.dto.Organization;
import org.bdware.irs.backend.services.BDGrsStorage;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import org.apache.log4j.Logger;
import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


//前后缀管理
public class BDGrsStorageRocksDBImpl implements BDGrsStorage {

    static Logger logger = Logger.getLogger(BDGrsStorageRocksDBImpl.class);
    RocksDB db;
    String dbPath;
    static String allOrg = "ALL_ORG";

    static {
        RocksDB.loadLibrary();
    }

    //op为0表示删除，1表示添加
    public void updateOrganizations(String doi, int op){
        Set<String> organizations;
        try {
            byte[] orgListBytes = db.get(allOrg.getBytes());
            if(orgListBytes == null)
                organizations = new HashSet<>();
            else{
                String orgListStr = new String(orgListBytes);
                organizations = new Gson().fromJson(orgListStr,new TypeToken<HashSet<String>>(){}.getType());
            }
            if(op == 1){
                organizations.add(doi);
            }else{
                organizations.remove(doi);
            }
            logger.info(new Gson().toJson(organizations));
            db.put(allOrg.getBytes(),  new Gson().toJson(organizations).getBytes());
        } catch (RocksDBException e) {
            e.printStackTrace();
        }
    }


    public BDGrsStorageRocksDBImpl(String dbPath){
        this.dbPath = dbPath;
        Options rockOpts = new Options().setCreateIfMissing(true);
        try {
            logger.info("rocksdb data path for grs: " + new File(dbPath).getAbsolutePath());
            db = RocksDB.open(rockOpts, dbPath);
        } catch (RocksDBException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    public BDGrsStorageRocksDBImpl(){
        this("./rocksdb_grs/");
    }


    protected RocksDB getDBInstance(){
        return db;
    }

    @Override
    public boolean saveOrganization(Organization organization) {
        logger.info(new Gson().toJson(organization));
        try {
            db.put(organization.getDoi().getBytes(), new Gson().toJson(organization).getBytes());
            updateOrganizations(organization.getDoi(), 1);
            return true;
        } catch (RocksDBException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean updateOrganization(Organization organization) {
        try {
            db.put(organization.getDoi().getBytes(), new Gson().toJson(organization).getBytes());
            return true;
        } catch (RocksDBException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public boolean deleteOrganization(Organization organization) {
        try {
            db.delete(organization.getDoi().getBytes());
            updateOrganizations(organization.getDoi(), 0);
            return true;
        } catch (RocksDBException e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public Organization getOrganization(String doi) {
        Organization organization = null;
        try {
            byte[] orgBytes = db.get(doi.getBytes());
            String orgStr = new String(orgBytes);
            organization = new Gson().fromJson(orgStr, Organization.class);
        } catch (RocksDBException e) {
            e.printStackTrace();
        } finally{
            return organization;
        }
    }

    @Override
    public List<Organization> getAllOrganization() {
        ArrayList<Organization> results = new ArrayList();
        byte[] orgListBytes = new byte[0];
        try {
            HashSet<String> organizations;
            orgListBytes = db.get(allOrg.getBytes());
            if(orgListBytes == null){
                organizations = new HashSet<>();
            }else{
                String orgListStr = new String(orgListBytes);
                organizations = new Gson().fromJson(orgListStr,new TypeToken<HashSet<String>>(){}.getType());
            }

            logger.info(new Gson().toJson(organizations));
            List<byte[]> ids = new ArrayList<>();
            for(String key : organizations){
                ids.add(key.getBytes());
            }
            List<byte[]> orgDetails = db.multiGetAsList(ids);
            for(byte[] orgByte : orgDetails){
                logger.info("org detail: " + new String(orgByte));
                results.add(new Gson().fromJson(new String(orgByte), Organization.class));
            }
        } catch (RocksDBException e) {
            e.printStackTrace();
        } finally{
            return results;
        }
    }
}
